package auth

import (
	"fmt"

	"github.com/emicklei/go-restful/v3"
	"github.com/infraboard/mcube/http/label"
	"github.com/infraboard/mcube/http/response"
	"github.com/infraboard/mcube/logger"
	"github.com/infraboard/mcube/logger/zap"

	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/code"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/permission"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/token"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/user"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/client/rpc"
)

// 给服务端提供的RESTful接口的 认证与鉴权中间件
func NewHttpAuther() (*HttpAuther, error) {
	return &HttpAuther{
		log: zap.L().Named("auther.http"),
		// 从全部变量获取
		client: rpc.C(),
	}, nil
}

// FilterFunction definitions must call ProcessFilter on the FilterChain to pass on the control and eventually call the RouteFunction
// type FilterFunction func(*Request, *Response, *FilterChain)

type HttpAuther struct {
	log logger.Logger
	// 基于rpc客户端进行封装
	client *rpc.ClientSet
}

// 是否开启权限的控制, 交给中间件使用方去觉得
func (a *HttpAuther) GoRestfulAuthFunc(req *restful.Request, resp *restful.Response, next *restful.FilterChain) {
	// 请求拦截
	route := req.SelectedRoute()
	meta := route.Metadata()
	a.log.Debugf("route meta: %s", meta)

	isAuth, ok := meta[label.Auth]
	// 有认证标签,并且开启了认证
	if ok && isAuth.(bool) {
		// 获取用户Token, Token放在Heander Authorization
		ak := token.GetTokenFromHTTPHeader(req.Request)

		// 调用GRPC 校验用户Token合法性
		tk, err := a.client.Token().ValidateToken(req.Request.Context(), token.NewValidateTokenRequest(ak))
		if err != nil {
			response.Failed(resp.ResponseWriter, err)
			return
		}

		// 是不是需要返回用户的认证信息: 那个人, 那个空间下面， token本身的信息
		req.SetAttribute("tk", tk)

		// 判断用户权限, 执行方形超级用户
		isPerm, ok := meta[label.Permission]
		if ok && isPerm.(bool) && tk.UserType != user.TYPE_SUPPER {
			ci, err := a.client.ClientInfo(req.Request.Context())
			if err != nil {
				response.Failed(resp.ResponseWriter, err)
				return
			}

			// 调用鉴权接口
			check := permission.NewCheckPermissionRequest()
			check.Domain = tk.Domain
			check.Namespace = tk.Namespace
			check.Username = tk.Username
			check.ServiceId = ci.Id
			check.Path = fmt.Sprintf("%s.%s", route.Method(), route.Path())
			perm, err := a.client.Permission().CheckPermission(req.Request.Context(), check)
			if err != nil {
				response.Failed(resp.ResponseWriter, err)
				return
			}
			a.log.Debugf("permission check pass: %s", perm)
		}

		// 判断用户是否开启二次认证, 用户每次操作危险接口都需要校验吗?
		isCode, ok := meta[label.Code]
		if ok && isCode.(bool) {
			// 进行验证码的校验, 需要获取用户传递的验证码
			// 我们的验证码也需要放到一个独立的Header中
			cd := code.GetCodeFromHTTP(req.Request)

			// 调用RPC进行 验证码校验,
			// 思考: 缓存用户验证的code, 用户code失效之前不需要再次验证
			codeReq := code.NewVerifyCodeRequest(tk.Username, cd)
			_, err := a.client.Code().VerifyCode(req.Request.Context(), codeReq)
			if err != nil {
				response.Failed(resp.ResponseWriter, err)
				return
			}
		}
	}

	// next flow
	next.ProcessFilter(req, resp)
}
